﻿using FastBuild.TimeJob;
using Newtonsoft.Json.Linq;
using SqlSugar;
using Wechat_PublicNumber.Common;
using Wechat_PublicNumber.Entity;
using Wechat_PublicNumber.Repository;

namespace Wechat_PublicNumber.Jobs
{
    [SkipWhileExecuting]
    public class PushStockJob : DataAccess, IJob
    {
        [Autowired]
        private CommonHttpInvoke _commonHttpInvoke;

        [Autowired]
        private WxTemplateRepository _templateRepository;

        [Autowired]
        private WxHttpInvoke _wxHttpInvoke;

        public async Task Execute()
        {
            try
            {
                var nowTime = DateTime.Now;

                var date = DateTime.Now.Date;

                //缓存不存在或者每天8点 都去刷新一次缓存
                if (nowTime == date.AddHours(8))
                    await _commonHttpInvoke.DownloadXueQiuOneStockPage("SZ000630");

                //周六日和假节日不开盘
                if (await WXDb.Queryable<HolidayTime>().Where(s => s.Type == Model.HolidayTypeEnum.Holiday && s.Time == nowTime.Date).AnyAsync()) return;

                //非股票交易时间
                if (nowTime < date.AddHours(9)
                        || (nowTime > date.AddHours(11).AddMinutes(30) && nowTime < date.AddHours(13))
                        || nowTime > date.AddHours(15))
                    return;

                //获取所有人的设置列表
                var allSet = await WXDb.Queryable<UserStock, Stock, UserInfo>((us, stock, users) => new object[]
                   {
                          JoinType.Inner, stock.ID== us.StockID,
                          JoinType.Inner, users.OpenID== us.OpenID
                   })
                 .Distinct()
                 .Select((us, stock, users) => new
                 {
                     stock.ID,
                     stock.StockName,
                     stock.StockCode,
                     stock.BelongStockExchange,
                     us.OpenID,
                     us.RemindChg,
                     us.RemindPercent,
                     us.RemindPrice
                 })
                 .ToListAsync();

                //获取所有股票
                var allStockCode = allSet.Select(s => s.BelongStockExchange.ToString() + s.StockCode).Distinct().ToList();
                if (allStockCode.Count <= 0) return;

                //一次取8条
                int onceCount = 8;
                int whileCount = allStockCode.Count / onceCount;
                if (allStockCode.Count % onceCount > 0) whileCount++;
                for (int i = 0; i < whileCount; i++)
                {
                    var allStock = await _commonHttpInvoke.GetRealTimeStock(string.Join(',', allStockCode.Skip(i * onceCount).Take(onceCount)));
                    var quoteObject = JObject.Parse(allStock);

                    foreach (var code in allStockCode)
                    {
                        var oneStock = quoteObject["data"].Where(s => s["symbol"].ToString() == code).FirstOrDefault();

                        if (oneStock == null) continue;

                        if (decimal.TryParse(oneStock["current"].ToString(), out decimal data_current)
                            && decimal.TryParse(oneStock["chg"].ToString(), out decimal data_chg)
                            && decimal.TryParse(oneStock["percent"].ToString(), out decimal data_percent))
                        {
                            //获取所有当前股票的用户
                            var oneStockUserList = allSet.Where(s => (s.BelongStockExchange.ToString() + s.StockCode) == code).ToList();

                            //预先载入模板所需参数
                            var remaidParm = new Model.Input.PublicNumberPushTemplate.StockWarningTemplateInput
                            {
                                stockName = $"{oneStockUserList[0].StockName}({oneStockUserList[0].BelongStockExchange.ToString() + oneStockUserList[0].StockCode})",
                                stockprice = data_current,
                                stockchg = data_chg,
                                stockpercent = data_percent
                            };

                            //偏移量 百分之0.15
                            var offsetPercent = 0.15M;
                            var offset = data_current * offsetPercent / 100;//价格和涨跌值不是百分比，所以要/100算出偏移量

                            //提醒股票价格到了
                            //提醒涨跌幅到了
                            //提醒涨跌幅百分比到了
                            var pushOpenIDList = oneStockUserList.Where(one =>
                                    (data_current != 0 && one.RemindPrice != 0 && data_current.BetweenOffset(one.RemindPrice, offset))
                                 || (data_chg != 0 && one.RemindChg != 0 && data_chg.BetweenOffset(one.RemindChg, offset))
                                 //涨跌百分比已经是百分比了 所以offsetPercent*100
                                 || (data_percent != 0 && one.RemindPercent != 0 && data_percent.BetweenOffset(one.RemindPercent, offsetPercent))
                                 ).Select(one => one.OpenID).Distinct().ToList();

                            //频率限制 每人每个股票5分钟推送一次
                            pushOpenIDList = await FilterFrequency(oneStockUserList[0].ID, pushOpenIDList);

                            //推送模板
                            var pushData = await _templateRepository.GetTemplateData(Model.WeChatTemplateEnum.StockWarning, pushOpenIDList, remaidParm);
                            if (pushData is not null)
                            {
                                await _wxHttpInvoke.PushTemplate(pushData);
                                await WXDb.Insertable(pushData.Select(s => new StockMonitorHistory()
                                {
                                    OpenID = s.touser,
                                    CreateTime = DateTime.Now,
                                    StockID = oneStockUserList[0].ID
                                }).ToList()).ExecuteCommandAsync();
                            }
                        }
                    }
                }
                _logger.Info($"PushStockJob Successfully executed", "PushStockJob");
                GC.Collect();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "PushStockJob Error", "PushStockJob");
            }
        }

        private async Task<List<string>> FilterFrequency(long stockID, List<string> openID)
        {
            return await WXDb.Queryable<UserStock, StockMonitorHistory>((us, sh) => new object[]
             {
                JoinType.Left,us.OpenID==sh.OpenID && us.StockID==sh.StockID
             })
             .Where((us, sh) => us.StockID == stockID && openID.Contains(us.OpenID))
             .GroupBy((us, sh) => us.OpenID)
             .Select((us, sh) => new
             {
                 us.OpenID,
                 MaxCreateTime = SqlFunc.AggregateMax(sh.CreateTime)
             })
             .MergeTable()
             .Where(s => s.MaxCreateTime.AddMinutes(5) <= DateTime.Now || ISNull("MaxCreateTime"))
             .Select(s => s.OpenID)
             .ToListAsync();
        }
    }
}
